#include <typescommon.h>
#include <genrand.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <queBase.h>
#include <errno.h>

#define shmOptInitFlag ((uint64_t)(0xa55a7d93cd23aeb6))

struct shmOptStruct
{
    key_t key;
    int fd;
    struct queOptStruct *qasPtr;
};

int shmOptInit(struct shmOptStruct *shm, key_t shmKey, uint32_t shmSize, int masterFlag)
{
    struct shmid_ds tmpShmInf;
    if (!shm)
    {
        logerror("");
        return -1;
    }
    shm->key = shmKey;
    shm->fd = shmget(shm->key, shmSize, IPC_CREAT | 0666);
    if (shm->fd < 0)
    {
        logerror("%d,%d:%d,%s", shm->key = shmKey, shm->fd, errno, strerror(errno));
        return -1;
    }
    shm->qasPtr = NULL;
    int tmpflag = shmctl(shm->fd, IPC_STAT, &tmpShmInf);
    if (tmpflag < 0)
    {
        logerror("%d,%d,%d:%d,%s", shm->key, shm->fd, tmpflag, errno, strerror(errno));
        return -1;
    }

    size_t shmOptSize = tmpShmInf.shm_segsz;
    logdebug("%d", (int)shmOptSize); // memery size
    if(shmSize != (uint32_t)shmOptSize)
    {
        logerror("%u != %u", (int32_t)shmSize, (int32_t)shmOptSize);
        // return -1;
    }

    //__shmflg set SHM_RDONLY if readonly.
    shm->qasPtr = (struct queOptStruct *)shmat(shm->fd, NULL, 0); // SHM_RDONLY
    if ((long)shm->qasPtr == -1 || !shm->qasPtr)
    {
        logerror("%d,%d,%p:%d,%s", shm->key, shm->fd, shm->qasPtr, errno, strerror(errno));
        return -1;
    }

    if (masterFlag)
    {
        queOptInit(shm->qasPtr, shmOptSize);
        // *(uint64_t *)(shm->qasPtr->usrInf) = shmOptInitFlag;
        // logdebug("0x%lx", *(uint64_t *)(shm->qasPtr->usrInf));
    }
    return 0;
}
int shmOptIsOk(struct shmOptStruct *shm)
{
    if (!(shm && shm->qasPtr))
    {
        logerror("");
        return -1;
    }
    // if (*(uint64_t *)(shm->qasPtr->usrInf) != shmOptInitFlag)
    // {
    //     logerror("0x%lx", *(uint64_t *)(shm->qasPtr->usrInf));
    //     return -1;
    // }
    return 0;
}
int shmOptFree(struct shmOptStruct *shm, int ismaster)
{
    if (!(shm && shm->qasPtr))
    {
        logerror("");
        return -1;
    }
    if (shm->qasPtr && (long)shm->qasPtr != -1)
    {
        // *(uint64_t *)(shm->qasPtr->usrInf) = 0;
        shmdt(shm->qasPtr);
        shm->qasPtr = NULL;
    }
    // if (!ismaster)
    // {
    //     return 0;
    // }
    if (shm->fd > 0)
    {
        shmctl(shm->fd, IPC_RMID, NULL);
        shm->fd = -1;
    }
    return 0;
}
uint32_t shmOptWrt(struct shmOptStruct *shm, const uint8_t *buff, uint32_t bsize)
{
    if (!shm)
    {
        logerror("");
        return 0;
    }
    if (shmOptIsOk(shm) < 0)
    {
        logerror("");
        return 0;
    }
    queOptWrite(shm->qasPtr, buff, bsize);
    return bsize;
}
uint32_t shmOptRd(struct shmOptStruct *shm, uint8_t rpin, uint8_t *buff, uint32_t bsize)
{
    if (!shm)
    {
        logerror("");
        return 0;
    }
    if (shmOptIsOk(shm) < 0)
    {
        logerror("");
        return 0;
    }
    return queOptRead(shm->qasPtr, rpin, buff, bsize);
}

int main(int argc, char **argv)
{
    struct shmOptStruct tmpOpt;
    sysTmrMsDefBegin(temTimer);
    if (argc < 2)
    {
        perror("param input error");
        return -1;
    }
    int tmpmaster = !!atoi(argv[1]);
    logdebug("this fork is %s", tmpmaster ? "master" : "sub");
    if (shmOptInit(&tmpOpt, 0x124acd, 1024, tmpmaster) < 0)
    {
        logerror("");
        return -1;
    }
    char tmpbf[128];
    while (sysTmrMsRunSec(temTimer) < 30)
    {
        if (tmpmaster)
        {
            snprintf(tmpbf, sizeof(tmpbf), "time now is ------------------------------------------------ : %016lu", systemNowMs());
            shmOptWrt(&tmpOpt, (const uint8_t *)tmpbf, strlen(tmpbf));
            usleep(200 * 1000);
        }
        else
        {
            usleep(50 * 1000);
            uint32_t tmpsize = shmOptRd(&tmpOpt, 0, (uint8_t *)tmpbf, sizeof(tmpbf) - 1); 
            if (tmpsize < 1)
            {
                continue;
            }
            tmpbf[sizeof(tmpbf) - 1] = 0;
            logdebug("read : %.*s", tmpsize, tmpbf);
        }
    }
    shmOptFree(&tmpOpt, tmpmaster);
    logdebug("fork quit: %s", tmpmaster ? "master" : "sub");
    return 1;
}
